#!/usr/bin/env python
# coding=utf-8

import os
import sys
import re
import codecs
import pickle

# set log
import CheckLog
log = CheckLog.get_file_log('OffsetDump.log')

# the offset dump program
VR_DIC_OFFSET_DUMP_TOOL = r'VrDicOffsetDump.exe'


class FetchPlaceError(Exception):pass


class KiwiPlace:
	def __init__(self, name, offset, voiceId, hasNextLevel):
		self._name = unicode(name)
		self._offset = int(offset)
		self._voiceId = int(voiceId)
		if 'Y' == hasNextLevel:
			hasNextLevel = True
		elif 'N' == hasNextLevel:
			hasNextLevel = False
		self._hasNextLevel = bool(hasNextLevel)
	
	def __getitem__(self, n):
		if 0 == n or 'name' == n:
			return self._name
		elif 1 == n or 'offset' == n:
			return self._offset
		elif 2 == n or 'voiceId' == n:
			return self._voiceId
		elif 3 == n or 'hasNextLevel' == n:
			return self._hasNextLevel
		else:
			return None
		
	def get_name(self):
		return self._name
	
	def get_offset(self):
		return self._offset
	
	def get_voiceId(self):
		return self._voiceId
	
	def has_next_level(self):
		return self._hasNextLevel	


class KiwiDataManager():
	def __init__(self, sKiwiFilepath):
		self._kiwiFilepath = sKiwiFilepath
		self._kiwiDataTree = None
		self._kiwiDataTree = self._fetch_places_tree()
	
	def fetch_frame(self, *sPlaces):
		all_places_tree = self._kiwiDataTree
		if 0 == len(sPlaces):
			d = all_places_tree
		elif 1 == len(sPlaces):
			d = all_places_tree[sPlaces[0]][1]
		elif 2 == len(sPlaces):
			d = all_places_tree[sPlaces[0]][1][sPlaces[1]][1]
		elif 3 == len(sPlaces):
			d = all_places_tree[sPlaces[0]][1][sPlaces[1]][1][sPlaces[2]][1]
		else: 
			raise KeyError()
		ret = ()
		for r in d.values():
			ret += r[0:1]
			ret += r[2:]
		return ret

	def fetch_record(self, *sPlaces):
		all_places_tree = self._kiwiDataTree
		if 1 == len(sPlaces):
			r = all_places_tree[sPlaces[0]]
			return r[0:1]+r[2:]
		elif 2 == len(sPlaces):
			r = all_places_tree[sPlaces[0]][1][sPlaces[1]]
			return r[0:1]+r[2:]
		elif 3 == len(sPlaces):
			r = all_places_tree[sPlaces[0]][1][sPlaces[1]][1][sPlaces[2]]
			return r[0:1]+r[2:]
		elif 4 == len(sPlaces):
			r = all_places_tree[sPlaces[0]][1][sPlaces[1]][1][sPlaces[2]][1][sPlaces[3]]
			return r[0:1]+r[2:]
		else: 
			raise KeyError()
		
	def get_same_place_number(self):
		all_places_tree = self._kiwiDataTree
		if 1 == len(sPlaces):
			return len(all_places_tree[sPlaces[0]]) - 2
		elif 2 == len(sPlaces):
			return len(all_places_tree[sPlaces[0]][1][sPlaces[1]]) - 2
		elif 3 == len(sPlaces):
			return len(all_places_tree[sPlaces[0]][1][sPlaces[1]][1][sPlaces[2]]) - 2
		elif 4 == len(sPlaces):
			return len(all_places_tree[sPlaces[0]][1][sPlaces[1]][1][sPlaces[2]][1][sPlaces[3]]) - 2
		else: 
			raise KeyError()

	def _fetch_frame_from_kiwi(self, sPlace1 = '', sPlace2 = '', sPlace3 = ''):
		ret = []
		sFolder, sFn = os.path.split(self._kiwiFilepath)
		cmdline = '%s %s %s %s %s %s'  \
			% (VR_DIC_OFFSET_DUMP_TOOL, sFolder, sFn, sPlace1, sPlace2, sPlace3)
		(pin, pout) = os.popen4(cmdline.encode('gbk'))
		lines = pout.readlines()
		if 0 == len(lines):
			log.error(r'<Read Pipe Error> : %s', cmdline)
			raise FetchPlaceError()
		lines = list(line.decode('gbk') for line in lines)
		if lines[0].find(r'ERROR') >= 0:
			log.error(r'<Get Place Error> : %s %s %s : %s', \
					sPlace1, sPlace2, sPlace3, lines[0])
			raise FetchPlaceError()
		for line in lines[1:]:
			r = re.match(r'(.+)\t\t(\d+)\t\t(\d+)\t\t([YN])', line)
			if not r:
				log.error(r'<Get Place Error> : %s %s %s : %s', 
						sPlace1, sPlace2, sPlace3, line)
				raise FetchPlaceError()
			ret.append(KiwiPlace(r.group(1), r.group(2), r.group(3), r.group(4)))
		return ret

	def _fetch_places_tree(self):
		if None != self._kiwiDataTree:
			return self._kiwiDataTree
		all_places = {}
		
		# fetch provinces
		for p in self._fetch_frame_from_kiwi():
			if all_places.has_key(p.get_name()):
				log.critical(r'%s has the same province !!!', p.get_name())
				raise KeyError()
			all_places[p.get_name()] = (p, {})
			
		#fetch cities
		for provName in all_places.keys():
			prov = all_places[provName][0]
			prov_next_frame = all_places[provName][1]
			for city in self._fetch_frame_from_kiwi(provName):
				if prov_next_frame.has_key(city.get_name()):
					log.critical(r'%s has the same city !!!', city.get_name())
					raise KeyError()
				prov_next_frame[city.get_name()] = (city, {})
		log.debug(r'Get cities OK')
		
		# fetch towns
		for provName in all_places.keys():
			prov = all_places[provName][0]
			prov_next_frame = all_places[provName][1]
			for cityName in prov_next_frame.keys():
				city = prov_next_frame[cityName][0]
				city_next_frame = prov_next_frame[cityName][1]
				if city.has_next_level():
					log.debug(r'Get towns of city - %s, city - %s', provName, cityName)
					for town in self._fetch_frame_from_kiwi(provName, cityName):
						if city_next_frame.has_key(town.get_name()):
							log.debug(r'%s has the same town/road !!', town.get_name())
							city_next_frame[town.get_name()] += (town,)
							continue
						city_next_frame[town.get_name()] = (town, {})

		# fetch roads
		for provName in all_places.keys():
			prov = all_places[provName][0]
			prov_next_frame = all_places[provName][1]
			for cityName in prov_next_frame.keys():
				city = prov_next_frame[cityName][0]
				city_next_level_frame = prov_next_frame[cityName][1]
				for townName in city_next_level_frame.keys():
					town = city_next_level_frame[townName][0]
					town_next_frame = city_next_level_frame[townName][1]
					if town.has_next_level():
						log.debug(r'Get roads of town - %s, city - %s, town - %s', provName, cityName, townName)
						for road in self._fetch_frame_from_kiwi(provName, cityName, townName):
							if town_next_frame.has_key(road.get_name()):
								log.debug(r'%s has the same name road !', road.get_name())
								town_next_frame[road.get_name()] += (road,)
								continue
							town_next_frame[road.get_name()] = (road, {})
		self._kiwiDataTree = all_places
		return self._kiwiDataTree

	def write_all_to_file(self, sFilename):
		all_places = self._fetch_places_tree()
		f = codecs.open(sFilename, 'w', encoding='utf-8')
		for provName in all_places.keys():
			prov = all_places[provName][0]
			f.write( '%s\t\t%d\t\t%d\t\t%s \n' % (prov.get_name(), prov.get_offset(), prov.get_voiceId(), prov.has_next_level())) 
			prov_next_frame = all_places[provName][1]
			for cityName in prov_next_frame.keys():
				city = prov_next_frame[cityName][0]
				f.write( '\t%s\t\t%d\t\t%d\t\t%s \n' % (city.get_name(), city.get_offset(), city.get_voiceId(), city.has_next_level())) 
				city_next_level_frame = prov_next_frame[cityName][1]
				for townName in city_next_level_frame.keys():
					town = city_next_level_frame[townName][0]
					f.write( '\t\t%s\t\t%d\t\t%d\t\t%s \n' % (town.get_name(), town.get_offset(), town.get_voiceId(), town.has_next_level())) 
					town_next_frame = city_next_level_frame[townName][1]
					for roadName in town_next_frame.keys():
						road = town_next_frame[roadName][0]
						f.write( '\t\t\t%s\t\t%d\t\t%d\t\t%s \n' % (road.get_name(), road.get_offset(), road.get_voiceId(), road.has_next_level())) 


def main():
	# parse parameters
	if len(sys.argv) != 3:
		print('Usage:')
		print('OffsetDump.py [Kiwi Index File Path] [output file]')
		sys.exit(0)
	kiwiFilePath = sys.argv[1]
	sOutFilename = sys.argv[2]
	
	# get places from KIWI
	kdm = KiwiDataManager(kiwiFilePath)
	# write to file
	kdm.write_all_to_file(sOutFilename)
	print("Dump all OK")

if __name__ == '__main__':
	main()

